<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>文件下载器</title>
</head>
<body>
  <div>
    <button onclick="downLoad()" id="start">开始</button>
    <button onclick="stopDownLoad()" id="stop">暂停</button>
    <button onclick="streamCanceclTest()" id="stop">测试</button>
  </div>
  <script type="text/javascript">
    let aborter = null
    const streamHandle = async (res) => {
      const total = res.headers.get('content-length')
      let loaded = 0
      const reader = res.body.getReader()
      const stream = new ReadableStream({
        start(controller) {
          let aborted = false
          const readLoop = async () => {
            const { value, done } = await reader.read()
            if (done) {
              if (!aborted) {
                console.log('下载完成')
                controller.close()
              }
              return 
            }
            loaded += value.length
            console.log(`Downloaded ${loaded} of ${total} (${(loaded / total * 100).toFixed(2)}%)`)
            setTimeout(() => {
              if (!aborted) {
                controller.enqueue(value)
                readLoop()
              }
            }, 100)
            
          } 
          aborter = () => {
            reader.cancel()
            controller.error('read stream cancel')
            aborted = true
          }
          readLoop()
        }
      })
      return new Response(stream, { headers: res.headers })
    }
    downLoad = async () => {
      const res = await fetch('./test.json')
      const logResult = await streamHandle(res)
      const jsonData = await logResult.json()
      console.log('readerDownload json--->', jsonData)
    }
    const stopDownLoad = () => {
      aborter && aborter()
    }

    const streamCanceclTest = () => {
      let aborter = null
      const abortHandler = (res) => {
          aborter = () => res.body.cancel()
          return res
      };
      fetch('./test.json').then(abortHandler).then(res => res.json())
      setTimeout(() => {
        aborter()
      }, 300)
    }
  </script>
</body>
</html>